#pragma once

#include <cassert>

template<typename T>
class RefCounted
{
public:

	RefCounted() : count_(NULL), ptr_(NULL)
	{}

	RefCounted(T* value) : ptr_(NULL), count_(value != NULL ? new size_t(0) : NULL)
	{}

	RefCounted(const RefCounted<T>& value) : ptr_(value.ptr_), count_(value.count_)
	{
		if (ptr_ != NULL)
			AddRef();
	}

	virtual ~RefCounted()
	{
		Release();
	}

	RefCounted<T>& operator=(const RefCounted<T>& rhs)
	{
		if (*this != rhs)
		{
			if (ptr_ != NULL)
				Release();

			ptr_ = rhs.ptr_;
			count_ = rhs.count_;
			if (ptr_ != NULL)
				AddRef();
		}
		return *this;
	}
	bool operator==(const RefCounted<T>& rhs) const
	{
		return ptr_ == rhs.ptr_;
	}
	bool operator!=(const RefCounted<T>& rhs) const
	{
		return ptr_ != rhs.ptr_;
	}
	const T& operator*() const
	{
		return *ptr_;
	}

	T& operator*()
	{
		return *ptr_;
	}
	const T* operator->() const
	{
		return ptr_;
	}

	T* operator->()
	{
		return ptr_;
	}

	bool IsValid() const
	{
		return ptr_ != NULL; 
	}


private:

	void AddRef()
	{
		assert(ptr_ != NULL);
		assert(count_ != NULL);
		++*count_;
	}

	void Release()
	{
		assert(ptr_ != NULL);
		assert(count_ != NULL);
		if (--*count_ == 0)
		{
			delete ptr_;
			delete count_;
			ptr_ = NULL;
			count_ = NULL;
		}
	}

private:

	size_t* count_;
	T* ptr_;
};
